﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NHibernate;
using FileTaggerData.Helpers;
using FileTaggerData.Domain;
using NHibernate.Criterion;
using System.Data.SQLite;

namespace FileTags
{
    public partial class FileForm : Form
    {
        public SearchForm Search { get; set; }
        public string FilePath { get; set; }
        public TaggedFile File { get; set; }
        private bool _fileIsNew;
        private List<FileTag> _allTags;
        private List<FileTag> _fileTags;
        private SQLiteConnection _conn; 

        public FileForm()
        {
            InitializeComponent();
        }

        private void btnSaveClose_Click(object sender, EventArgs e)
        {
            using (ISession session = FactoryHolder.GetSession())
            {
                ITransaction trans = session.BeginTransaction();
                try
                {
                    if (!_fileIsNew)
                    {
                        _fileTags = new List<FileTag>(File.Tags);
                        session.Refresh(File);
                        File.Tags.Clear();
                        foreach (var item in _fileTags)
                        {
                            FileTag tag = (FileTag)item;
                            session.Refresh(tag);
                            File.Tags.Add(tag);
                        }
                    }
                    File.Description = txtDescription.Text == string.Empty? null : txtDescription.Text;
                    session.SaveOrUpdate(File);
                    trans.Commit();
                    this.Close();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void FileForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            Application.Exit();
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            if (Search == null)
            {
                Search = new SearchForm();
            }

            Search.Show();
        }

        private void btnAddTag_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtNewTag.Text) || string.IsNullOrWhiteSpace(txtNewTag.Text))
            {
                MessageBox.Show(this, "Please insert tag name", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                using (ISession session = FactoryHolder.GetSession())
                {
                    ITransaction trans = session.BeginTransaction();
                    try
                    {
                        FileTag tag = new FileTag
                        {
                            Name = txtNewTag.Text
                        };

                        session.Save(tag);
                        trans.Commit();

                        _allTags.Add(tag);
                        lstAllTags.Items.Add(tag);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        trans.Rollback();
                    }
                }
            }
        }

        private void FileForm_Load(object sender, EventArgs e)
        {
            using (ISession session = FactoryHolder.GetSession())
            {
                ICriteria cr = session.CreateCriteria<FileTag>();
                _allTags = new List<FileTag>(cr.List<FileTag>());

                
                cr = session.CreateCriteria<TaggedFile>().Add(Expression.Eq("FilePath",FilePath));
                File = cr.UniqueResult<TaggedFile>();
                if (File == null)
                {
                    File = new TaggedFile
                    {
                        FilePath = FilePath,
                        Tags = new List<FileTag>()
                    };

                    _fileIsNew = true;
                }
                else
                {
                    _fileIsNew = false;
                    txtDescription.Text = File.Description;
                }

                UpdateAllTags();
                UpdateFileTags();
            }
        }

        private void editTagMenuItem_Click(object sender, EventArgs e)
        {
            TagEditForm editForm = new TagEditForm();
            editForm.Tag = (FileTag)lstAllTags.SelectedItem;
            DialogResult res = editForm.ShowDialog(this);
            if (res == System.Windows.Forms.DialogResult.OK)
            {
                _allTags.Remove(editForm.Tag);
                _allTags.Add(editForm.Tag);
                UpdateAllTags();
            }
        }

        private void deleteTagMenuItem_Click(object sender, EventArgs e)
        {
            FileTag tag = (FileTag)lstAllTags.SelectedItem;
            if (tag == null)
            {
                MessageBox.Show(this, "Tag is not selected", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            using (ISession session = FactoryHolder.GetSession())
            {
                ITransaction trans = session.BeginTransaction();
                try
                {
                   session.Refresh(tag);
                   session.Delete(tag);
                   trans.Commit();
                   _allTags.Remove(tag);
                   UpdateAllTags();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }                
            }
        }

        private void btnMoveSelectedTo_Click(object sender, EventArgs e)
        {
            FileTag tag = (FileTag)lstAllTags.SelectedItem;
            if (tag == null)
            {
                MessageBox.Show(this, "Tag is not selected", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            File.Tags.Add(tag);
            UpdateAllTags();
            UpdateFileTags();
        }

        private void UpdateFileTags(Func<FileTag,bool> filter = null)
        {
            if (filter == null)
            {
                filter = delegate(FileTag tag)
                {
                    return true;
                };
            }

            var q = from ft in File.Tags where filter(ft) select ft;
            lstFileTags.Items.Clear();

            foreach (FileTag item in q)
            {
                lstFileTags.Items.Add(item);
            }

            if (lstFileTags.Items.Count > 0)
            {
                lstFileTags.SelectedIndex = 0;
            }
            
        }

        private void UpdateAllTags(Func<FileTag,bool> filter = null)
        {
            if (filter == null)
            {
                filter = delegate(FileTag tag)
                {
                    if (File == null)
                    {
                        return true;
                    }
                    else
                    {
                        if (File.Tags == null)
                        {
                            return true;
                        }
                        else
                        {
                            return !File.Tags.Contains(tag);
                        }
                    }
                };
            }

            var q = from ft in _allTags where filter(ft) select ft;
            lstAllTags.Items.Clear();
            foreach (FileTag item in q)
            {
                lstAllTags.Items.Add(item);
            }

            if (lstAllTags.Items.Count > 0)
            {
                lstAllTags.SelectedIndex = 0;
            }
        }

        private void btnMoveSelectedBack_Click(object sender, EventArgs e)
        {
            FileTag toRemove = (FileTag)lstFileTags.SelectedItem;

            if (toRemove != null)
            {
                if (File != null && File.Tags != null)
                {
                    File.Tags.Remove(toRemove);
                    UpdateAllTags();
                    UpdateFileTags();
                }
            }
        }
    }
}
